#define NULL 0
#define va_start(ap,v)  ( ap = (va_list)&v + sizeof(v) )
#define va_arg(ap,t)    (*(t *)(ap = ap + sizeof(t), ap - sizeof(t)))
#define va_end(ap)      ( ap = (va_list)0 )	

#define MAX_TASK_NUM 4
#define KERNEL_STACK_SIZE 56*8

typedef char *  va_list;
/* 存储段描述符/系统段描述符 */
typedef struct s_descriptor		/* 共 8 个字节 */
{
	unsigned short	limit_low;		/* Limit */
	unsigned short	base_low;		/* Base */
	unsigned char	base_mid;		/* Base */
	unsigned char	attr1;			/* P(1) DPL(2) DT(1) TYPE(4) */
	unsigned char	limit_high_attr2;	/* G(1) D(1) 0(1) AVL(1) LimitHigh(4) */
	unsigned char	base_high;		/* Base */
} DESCRIPTOR;

/* 门描述符 */
typedef struct s_gate
{
	unsigned short	offset_low;	/* Offset Low */
	unsigned short	selector;	/* Selector */
	unsigned char	dcount;		/* 该字段只在调用门描述符中有效。如果在利用
				   调用门调用子程序时引起特权级的转换和堆栈
				   的改变，需要将外层堆栈中的参数复制到内层
				   堆栈。该双字计数字段就是用于说明这种情况
				   发生时，要复制的双字参数的数量。*/
	unsigned char	attr;		/* P(1) DPL(2) DT(1) TYPE(4) */
	unsigned short	offset_high;	/* Offset High */
} GATE;

typedef void (*int_handler)();

struct Thread {
	unsigned long ip;
	unsigned long sp;
};

typedef struct PCB{
	int pid;
	volatile long state; //-1 unrunnable, 0 runnable, >0 stopped
	char stack[KERNEL_STACK_SIZE];
	//CPU-specific state of this task
	struct Thread thread;
	unsigned long task_entry;
	struct PCB *next;
} tPCB;

typedef void (*int_handler)();
//用于加载入寄存器


GATE idt[256];
char idt_ptr[6];

int myprint(char * c, ...);//简陋的打印函数，c为要打印的字符串指针
void *memcpy(void *to, void *from, unsigned long size);//简陋的memcpy，from为开始位置，to为目的位置，size为长度
unsigned char in_byte(int port);//端口输入
void out_byte(int port,char value);//端口输出
int get_cursor();//获得光标
void set_cursor(int p);//设置光标
void init_idt_desc(unsigned char vector, unsigned char desc_type,int_handler handler, unsigned char privilege);//初始化中断门

void general_interrupt_handler();//通用中断处理
void c_general_interrupt_handler();

void general_exception_handler();//通用异常处理
void c_general_exception_handler();//通用异常处理

void r_0x06_exception_handler();//6号异常处理

void rtm_0x70_interrupt_handle();//实时时钟中断处理过程（切换程序例程）
void r_0x70_interrupt_handle();//实时时钟中断处理过程（切换程序例程）

tPCB task[MAX_TASK_NUM];
tPCB *my_current_task = NULL;
volatile int my_need_sched = 0;
volatile int time_count = 0;

void my_process(void);
void my_schedule(void);

void my_start_kernel(void)
{
	int pid = 0;
	int i;
	myprint("\nmy_start_kernel open\n");
	//Initialize process 0
	task[pid].pid = pid;
	task[pid].state = 0;
	task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process;
	task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];
	task[pid].next = &task[pid];
	//fork more process
	
	for(i=1; i<MAX_TASK_NUM; i++) {
		memcpy(&task[i], &task[0], sizeof(tPCB));
		task[i].pid = i;
		task[i].state = 0;//-1 unrunnable, 0 runnable, >0 stopped
		task[i].thread.sp = (unsigned long)&task[i].stack[KERNEL_STACK_SIZE-1];
		task[i].next = task[i-1].next;
		task[i-1].next = &task[i];
	}
	myprint("fork more process end\n");
	//start process 0 by task[0]
	pid = 0;
	my_current_task = &task[pid];
	myprint("%d\n",(int )(my_current_task->pid));
	myprint("start process 0 by task[0]\n");
	asm volatile(
		"movl %1,%%esp\n\t"
		"pushl %1\n\t"
		"pushl %0\n\t"
		"ret\n\t"
		"popl %%ebp\n\t"
		:
		: "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)
	);
	asm("hlt");
}

void my_process(void)
{
	int i = 0;
	while(1) {
		i++;
		if(i%1000000 == 0) {
			myprint("this is process %d -\n",(int )(my_current_task->pid));
			if (my_need_sched == 1) {
				my_need_sched = 0;
				my_schedule();
			}
		}
	}
}

void my_timer_handler(void)
{
#if 1
	if (time_count%10 == 0 && my_need_sched != 1) {
		myprint(">>>my_timer_handler here<<<\n");
		my_need_sched = 1;
	}
	time_count++;
#endif
	return;
}

inline void my_schedule(void)
{
	tPCB *next;
	tPCB *prev;
	
	if(my_current_task == NULL
		|| my_current_task->next == NULL) {
		return;
	}
	myprint(">>>my_schedule<<<\n");

	//schedule

	next = my_current_task->next;
	prev = my_current_task;
	if (next->state == 0) {
		my_current_task = next;
		myprint(">>>switch %d to %d<<<\n", prev->pid, next->pid);
	
    		asm volatile(	
        		"pushl %%ebp\n\t" 	    /* save rbp of prev */
        		"movl %%esp,%0\n\t" 	/* save rsp of prev */
        		"movl %2,%%esp\n\t"     /* restore  rsp of next */
        		"movl $1f,%1\n\t"       /* save rip of prev */	
        		"pushl %3\n\t" 
        		"ret\n\t" 	            /* restore  rip of next */
        		"1:\t"                  /* next process start here */
        		"popl %%ebp\n\t"
        		: "=m" (prev->thread.sp),"=m" (prev->thread.ip)
        		: "m" (next->thread.sp),"m" (next->thread.ip)
    		); 
	}
	return;
}
//----------------------------------------------------------------------------------------------------------------
void Init_idt()
{
	int i;
	for (i=0; i<20; i++) {
		init_idt_desc(i, 0x8e,general_exception_handler, 0x00);
	}
	for (; i<256; i++) {
		init_idt_desc(i, 0x8e,general_interrupt_handler, 0x00);
	}
	init_idt_desc(0x70, 0x8e,rtm_0x70_interrupt_handle, 0x00);
}

void Init_timer()//初始化实时时钟中断处理过程，准备开放中断
{
	short * p_idt_limit = (short *)(&idt_ptr[0]);
	int * p_idt_base  = (int *)(&idt_ptr[2]);
	*p_idt_limit = 256*8-1;
	*p_idt_base  = (int)&idt;
	asm ("lidt (idt_ptr)");
}

void Init_8259A()//设置8259A中断控制器
{
	unsigned char TEMP;
	//设置8259A中断控制器
	out_byte(0x20,0x11);//ICW1：边沿触发/级联方式
	out_byte(0x21,0x20);//ICW2:起始中断向量
	out_byte(0x21,0x04);//ICW3:从片级联到IR2
	out_byte(0x21,0x01);//ICW4:非总线缓冲，全嵌套，正常EOI

	out_byte(0xa0,0x11);//ICW1：边沿触发/级联方式
	out_byte(0xa1,0x70);//ICW2:起始中断向量
	out_byte(0xa1,0x04);//ICW3:从片级联到IR2
	out_byte(0xa1,0x01);//ICW4:非总线缓冲，全嵌套，正常EOI

	
         //设置和时钟中断相关的硬件
	out_byte(0x70,0x8b);//阻断NMI
	out_byte(0x71,0x12);
	TEMP=in_byte(0xa1);//读8259从片的IMR寄存器
	TEMP=TEMP & 0xfe;//清除bit 0(此位连接RTC)
	out_byte(0xa1,TEMP);//写回此寄存器
	out_byte(0x70,0x0c);
	in_byte(0x71);
	
	asm("sti");//开放中断
	myprint("%d",(int)TEMP);
}
void Init_print()//初始化屏幕
{
	set_cursor(0);
	char *a=">>This is a text<<\nCan I say something personal here??\nOh,it is a simple thing:\nI love my baby pig Gan!!\n\0";
	int b=256;
	myprint(a);
	myprint("test:%d",b);
}

void cstart()
{
	Init_idt();
	Init_timer();
	Init_8259A();
	Init_print();
	my_start_kernel();
	while(1);
}	

int get_cursor()//获取光标地址
{
	int pt;
	out_byte(0x3d4,0x0e);
	pt = (int)in_byte(0x3d5);
	out_byte(0x3d4,0x0f);
	pt = pt<<8;
	pt = pt | (int)in_byte(0x3d5);
	return pt;
}

void set_cursor(int p)//放置光标地址
{
	int pt;
	pt = p;
	out_byte(0x3d4,0x0f);
	out_byte(0x3d5,(char)pt);
	pt = pt>>8;
	out_byte(0x3d4,0x0e);
	out_byte(0x3d5,(char)pt);
}
void print_Dec (unsigned int n)
{
	char *a="x\0";
	if (n >= 10) {
        	print_Dec(n / 10); 
        	n %= 10;
	}
	*a=(char)(n + '0');
	myprint(a);
}

int myprint(char * c, ...)
{
	int pt,i,n;
	int fmt;
	char *p=(char *)(0x800b8000);
	va_list argp;
	asm("cli");
	pt = get_cursor();
	
	va_start(argp, c);
	for(n = 0; c[n] !='\0' && pt < 80*25; n++) {
		if(c[n] == '%' && c[n+1] == 'd') {
			fmt = va_arg(argp, long * );
			print_Dec(fmt);
			pt = get_cursor();
			n++;
		}else if(c[n] == '\n') {
			pt = (80-pt%80)+pt;
		} else {
			*(p+pt*2)=c[n];
			pt++;
		}
		if(pt >= 80*25) {
			memcpy(p, p+80*2, 80*24*2);
			for(i=0; i<80;i++) {
				*(p+80*24*2+i*2)=NULL;
			}
			pt =80*24;
		}
		set_cursor(pt);
	}
	va_end(c);
	asm("sti");
	return 0;
}


void *memcpy(void *to, void *from, unsigned long size)
{
	char *tempFrom;
	char *tempTo;
	tempFrom = from;
	tempTo   = to;
	while(size > 0) {
		*tempTo = *tempFrom;
		tempTo++;
		tempFrom++;
		size--;
	}
	return to;
}

void out_byte(int port,char value)
{
	asm volatile(
	"movl %0,%%edx\n\t"
	"movb %1,%%al\n\t"
	"outb %%al,%%dx\n\t"
	"nop\n\t"
	"nop"
	:
	:"m"(port),"m"(value)
	:"eax","dx"
	);
}

unsigned char in_byte(int port)
{
	unsigned char rt;
	asm volatile(
		"movl %1,%%edx\n\t"
		"inb %%dx,%%al\n\t"
		"movb %%al,%0\n\t"
		"nop\n\t"
		"nop"
		:"=r"(rt)
		:"m"(port)
	);
	return rt;
}

void c_general_interrupt_handler()
{
	out_byte(0xa0,0x20);
	out_byte(0x20,0x20);
}

void c_general_exception_handler()
{
	myprint("********Exception encounted********\n");
	asm("hlt");
}

void init_idt_desc(unsigned char vector, unsigned char desc_type,int_handler handler, unsigned char privilege)
{
	GATE *p_gate = &idt[vector];
	unsigned int base	= (unsigned int)handler;
	p_gate->offset_low	= base & 0xFFFF;
	p_gate->selector	= 0x08;//CS段选择子
	p_gate->dcount		= 0;
	p_gate->attr		= desc_type | (privilege << 5);
	p_gate->offset_high	= (base >> 16) & 0xFFFF;
}

void c_rtm_0x70_interrupt_handle()//实时时钟中断处理过程（切换程序例程）
{
	out_byte(0xa0,0x20);
	out_byte(0x20,0x20);
	out_byte(0x70,0x0c);
	in_byte(0x71);
	//myprint("********open_rtm_0x70_interrupt_handle********\n");
	my_timer_handler();
}
